unit LuaBindings;

interface
uses lua, luautils, WorldI, ScriptEngineI, coreI, GameObjects, inputI;

Procedure RegisterLuaBindings; cdecl;
Procedure ProcessGameEvent(ge:PGameEvent);
Procedure ProcessInputActionEvent(e:PInputAction; code:integer);
Procedure ProcessTimerEvent(obj:TBasicObject; data:TScriptReference);
Procedure ProcessCollisionEvent(self, victim:TGenericObject);
Procedure ProcessEndFreeFallEvent(obj:TDynamicObject; speed:single);
Procedure FreeParameterReference(ref:TScriptReference);
var world:IWorld;
implementation
uses common, sysutils, VectorGeometry, ObjectsHelper;
const
ObjTableName = '_Objects';
ProcessEventsMethodName = 'processEvents';
var
l:lua_state;
LuaI:ILua;

Function LuaToBasicObject(l:Lua_State; index:integer):TBasicObject; cdecl;
                    begin
                    luaCheckTableType(l, index, 'LuaToBasicObject');
lua_pushvalue(l, luaAbsIndex(l, index));
lua_pushstring(l, '_self');
lua_RawGet(l, -2);
result := pointer(lual_checkudata(l, -1, 'GameObject')^);
lua_pop(l, 2);
                    end;

                    Function LuaGetParameterReference(l:lua_state; index:integer):TScriptReference;
                    begin
result:=luaL_ref(L, LUA_REGISTRYINDEX);
                    end;

Procedure LuaPushParameterByReference(l:lua_state; ParamRef:TScriptReference; free:boolean=false);
begin
lua_rawgeti(L, LUA_REGISTRYINDEX, ParamRef);
if free then lual_unref(l, lua_RegistryIndex, paramref);
end;
Procedure FreeParameterReference(ref:TScriptReference);
begin
lual_unref(l, lua_RegistryIndex, ref);
end;
Procedure LuaPushGameObjectsTable(l:lua_state);
begin
lua_getfield(l, lua_globalsindex, ObjTableName);
end;

procedure LuaPushGameObjectByReference(l:lua_state; objref:TScriptReference);
begin
LuaPushGameObjectsTable(l);
lua_rawgeti(l, -1, objref);
lua_remove(l, -2);
end;

Function LuaNewGameObjectReference(l:lua_state; index:integer):TScriptReference;
var i:integer;
                                        begin
                                        i:=LuaAbsIndex(l, index);
                                        LuaPushGameObjectsTable(l);
                                        lua_PushValue(l, i);
result:=lual_Ref(l, -2);
lua_pop(l, 1);
                                        end;

Procedure LuaNilGameObjectReference(l:lua_state; ObjRef:TScriptReference);
                               begin
LuaPushGameObjectsTable(l);
Lua_PushNil(l);
Lua_RawSetI(l, -2, ObjRef);
Lua_Pop(l, 1);
                               end;

                    Function LuaWorld_PushGameEvent(l:lua_state):integer; cdecl;
var obj:pointer;
code:cardinal;
data:pointer;
begin
if lua_GetTop(l) <> 3 then
lual_Error(l, 'world.PushGameEvent expects 3 parameters (obj, code, event).', []);
obj:=LuaToBasicObject(l, 1);
             code:=lua_ToInteger(l, 2);
             //data processing here
if not lua_isnil(l, 3) then data:=Pointer(LuaGetParameterReference(l, 3)) else
data := nil;
world^.PushGameEvent(obj, code, data);
result:=0;
end;

Procedure LuaPushBasicObject(l:lua_state; index:integer; obj:pointer);
var PObj:^pointer;
begin
Lua_PushValue(l, LuaAbsIndex(l, index));
LuaCheckTableType(l, index, 'LuaPushBasicObject');
lua_PushString(l, '_self');
PObj := lua_newUserData(l, sizeof(pointer));
PObj^ := obj;
lual_getmetatable(l, 'GameObject');
lua_setmetatable(l, -2);
lua_rawset(l, -3);
lua_pop(l, 1); //PushValue
end;

Procedure LuaPushGameObjectMethod(l:lua_state; obj:TBasicObject; method:string; pushself:boolean=true);
begin
LuaPushGameObjectByReference(l, obj.ScriptReference);
luapushstring(l, Method);
lua_gettable(l, -2);
LuaCheckFunctionType(l, -1, 'LuaPushGameObjectMethod');
if PushSelf then Lua_PushValue(l, -2);
end;

Procedure ProcessGameEvent(ge:PGameEvent);
begin
LuaPushGameObjectMethod(l, TBasicObject(ge^.obj), ProcessEventsMethodName);
lua_pushinteger(l, EVENT_GAMEACTION);
Lua_CreateTable(l, 0, 2);
luapushstring(l, 'code');
Lua_PushInteger(l, ge^.code);
lua_rawset(l, -3);
                       luaPushString(l, 'data');
if integer(ge^.data) <> lua_noref then luaPushParameterByReference(l, TScriptReference(ge^.data))
else lua_pushnil(l);
lua_rawset(l, -3);
try
LuaPCall(l, 3, 0, 0); //first parameter (self) was pushed by LuaPushGameObjectMethod
except
on e:Exception do core_Error(PChar('Error while calling processEvent method (EVENT_GAMEACTION): ' + e.Message), ECore_Main);
end;
end;

Procedure ProcessCollisionEvent(self, victim:TGenericObject);
begin
LuaPushGameObjectMethod(l, self, ProcessEventsMethodName);
                                                                          lua_pushinteger(l, WORLDEVENT_COLLISION);
Lua_createtable(l, 0, 1);
luapushstring(l, 'victim');
luaPushGameObjectByReference(l, victim.ScriptReference);
lua_rawset(l, -3);
try
LuaPCall(l, 3, 0, 0); //first parameter (self) was pushed by LuaPushGameObjectMethod
except
on e:Exception do core_Error(PChar('Error while calling processEvent method (WORLDEVENT_COLLISION): ' + e.Message), ECore_Main);
end;
                                                                          end;

Procedure ProcessInputActionEvent(e:PInputAction; code:integer);
begin
LuaPushGameObjectMethod(l, TBasicObject(e^.data1), ProcessEventsMethodName);
lua_pushinteger(l, EVENT_INPUTACTION);
lua_CreateTable(l, 0, 3);
                         luapushstring(l, 'pressed');
if code = INPUTACTION_DOWN then lua_pushboolean(l, true) else lua_pushboolean(l, false);
lua_rawset(l, -3);
LuaPushString(l, 'action');
lua_PushInteger(l, e^.action);
lua_RawSet(l, -3);
luaPushString(l, 'data');
if TScriptReference(e^.data2) <> lua_noref then
luaPushParameterByReference(l, TScriptReference(e^.data2))
else lua_pushnil(l);
lua_rawset(l, -3);
try
LuaPCall(l, 3, 0, 0); //first parameter (self) was pushed by LuaPushGameObjectMethod
except
on e:Exception do core_Error(PChar('Error while calling processEvent method (EVENT_INPUTACTION): ' + e.Message), ECore_Main);
end;
end;

Procedure ProcessTimerEvent(obj:TBasicObject; data:TScriptReference);
begin
LuaPushGameObjectMethod(l, obj, ProcessEventsMethodName);
lua_pushinteger(l, WORLDEVENT_TIMER);
if Data <> lua_noref then luaPushParameterByReference(l, data) else lua_pushnil(l);
try
LuaPCall(l, 3, 0, 0); //first parameter (self) was pushed by LuaPushGameObjectMethod
except
on e:Exception do core_Error(PChar('Error while calling processEvent method (WORLDEVENT_TIMER): ' + e.Message), ECore_Main);
end;
end;

    Function LuaWorldInit(l:lua_state):integer; cdecl;
var gravity:TVector3F;
    begin
if (lua_gettop(l) < 2) or (lua_gettop(l) > 3)  then
lual_error(l, 'world.init expects 3 parameters (size, ambientReverb, gravityVector).', []);
if lua_gettop(l) = 3 then
gravity := LuaI^.luaToVector3F(l, 3)
else gravity := AffineVectorMake(0,0,0);
world^.Init(lua_tonumber(l, 1), lua_tostring(l, 2), gravity);;
result:=0;
    end;

    Function LuaWorldRelease(l:lua_state):integer; cdecl;
var ReleaseUnmanaged:boolean;
    begin
if lua_gettop(l) > 1 then
lual_error(l, 'world.release expects 1 parameter (releaseUnmanaged=false).', []);
if lua_gettop(l) = 1 then
ReleaseUnmanaged := lua_toboolean(l, 1) else
ReleaseUnmanaged := false;
world^.Release(ReleaseUnmanaged);
result:=0;
    end;

Function LuaWorldCreateBasicObject(l:lua_state):integer;     cdecl;
var flags:cardinal;
    begin
if (lua_GetTop(l) < 1) or (Lua_GetTop(l) > 2) then
lual_Error(l, 'world.createBasicObject expects 2 parameters (obj, flags).', []);
if lua_gettop(l) = 2 then flags := strtoflags(luaToString(l,2)) else flags := 0;
LuaPushBasicObject(l, 1, world_CreateBasicObject(LuaNewGameObjectReference(l, 1), flags));
result:=0;
    end;

Function LuaWorldReleaseGameObject(l:Lua_State):integer; cdecl;
var obj:TBasicObject;
    begin
if lua_gettop(l) <>1 then
lual_error(l, 'world.releaseObject expects 1 parameter (obj).', []);
obj:=LuaToBasicObject(l, 1);
LuaNilGameObjectReference(l, obj.ScriptReference);
world_ReleaseGameObject(obj);
result:=0;
    end;
Function LuaObjSetFlag(l:lua_state):integer; cdecl;
var obj:TBasicObject;
begin
if lua_gettop(l) <> 2 then lual_error(l, 'obj.setFlag expects 2 parameters (obj, flag).', []);
                     obj := LuaToBasicObject(l, 1);
obj.flags := obj.flags or STRToFlags(luaToString(l, 2));
result:=0;
end;
Function LuaObjIsFlagset(l:lua_state):integer; cdecl;
var obj:TBasicObject;
flags:cardinal;
begin
if lua_gettop(l) <> 2 then lual_error(l, 'obj.IsFlagSet expects 2 parameters (obj, flag).', []);
obj := LuaToBasicObject(l, 1);
flags := StrToFlags(LuaToString(l, 2));
lua_pushboolean(l, obj.flags and flags = flags);
result:=1;
end;

function LuaObjRegisterInputActionMap(l:lua_state):integer; cdecl;
var obj:TBasicObject;
s:string;
begin
if                     lua_gettop(l) <> 2 then
lual_error(l, 'obj.registerInputActionMap expects 2 parameters (obj, map).', []);
obj := LuaToBasicObject(l, 1);
if not world_GameObjectExists(obj) then begin
log_write('obj.registerInputActionMap: warning: trying to access not existing object', ll_warn);
result:=0;
exit;
end;
lua_pushnil(l);
while lua_next(l, 2) <> 0 do begin
if lua_isstring(l, -1) then
obj.AddInputAction(lua_tostring(l, -1), lua_tointeger(l, -2), lua_noref)
else if lua_istable(l, -1) then begin //value is table. first is keysym, second - some data
lua_rawgeti(l, -1, 1); //keysym
lua_rawgeti(l,-2, 2); //data
s := lua_tostring(l, -2);
obj.AddInputAction(s, lua_tointeger(l, -4), LuaGetParameterReference(l, -1));
lua_pop(l, 1);
end;
lua_pop(L, 1);
end;
result:=0;
end;

Function LuaObjAcquireInput(l:lua_state):integer; cdecl;
var obj:TBasicObject;
begin
if lua_gettop(l) <> 1 then
lual_error(l, 'obj.acquireInput expects 1 parameter (obj).', []);
obj:=luaToBasicObject(l, 1);
if world_GameObjectExists(obj) then
obj.RegisterInputActions() else
log_write('obj.acquireInput: warning: trying to access not existing object', ll_warn);
                                                                                      result:=0;
end;

function LuaObjUnacquireInput(l:lua_state):integer; cdecl;
var obj:TBasicObject;
begin
                    if lua_gettop(l) <> 1 then
                    lual_error(l,'obj.unacquireInput expects 1 parameter (obj).', []);
                    obj:=LuaToBasicObject(l, 1);
                    if world_GameObjectExists(obj) then
                    obj.UnregisterInputActions else
                    log_write('obj.unacquireInput: warning: trying to access not existing object', ll_warn);
                    result:=0;
                    end;

Function LuaToAffineMatrix(l:lua_state; i:integer):TAffineMatrix;
var j, index:integer;
begin
index := LuaAbsIndex(l, i);
LuaCheckTableType(l, index, 'LuaToAffineMatrix');
lua_pushnil(l);
j:=0;
while lua_next(l, index) <> 0 do begin
result[j] := LuaI^.LuaToVector3F(l, -1);
lua_pop(l, 1);
inc(j);
end;
end;
Function LuaToGeometricalPrimitive(l:lua_state; i:integer):TGeometricalPrimitive;
var index:integer;
begin
index:=LuaAbsIndex(l, i);
luaCheckTableType(l, index, 'luaToGeometricalPrimitive');
Lua_GetField(l, index, 'type');
lual_CheckInteger(l, -1);
result._type := TGeometricalPrimitiveType(Lua_ToInteger(l, -1));
lua_pop(l, 1);
case result._type of
GP_Sphere: begin
lua_GetField(l, index, 'radius');
Lual_CheckNumber(l, -1);
result.radius := Lua_ToNumber(l, -1);
end;
GP_AABB, GP_OBB: begin
Lua_GetField(l, index, 'width');
lual_CheckNumber(l, -1);
result.Size[0] := Lua_ToNumber(l, -1);
lua_pop(l, 1);
lua_GetField(l, index, 'height');
lual_CheckNumber(l, -1);
result.Size[1] := Lua_ToNumber(l, -1);
lua_pop(l, 1);
Lua_GetField(l, index, 'length');
lual_CheckNumber(l, -1);
result.Size[2] := Lua_ToNumber(l, -1);
lua_pop(l, 1);
Lua_GetField(l, index, 'orientation');
   if lua_istable(l,-1) then
   result.orientation := LuaToAffineMatrix(l, -1) else
   result.orientation := IdentityMatrix;
lua_pop(l, 1);
                                        end;
                                        GP_Ray: begin
Lua_GetField(l, index, 'start');
luaCheckTableType(l, -1, 'LuaToPrimitive (GP_RAY: start)');
result.startPoint := LuaI^.LuaToVector3F(l, -1);
lua_pop(l, 1);
lua_GetField(l, index, 'direction');
                                                           luaCheckTableType(l, -1, 'LuaToPrimitive (GP_RAY: direction)');
result.direction := luaI^.LuaToVector3F(l, -1);
lua_pop(l, 1);
lua_GetField(l, index, 'length');
lual_CheckNumber(l, -1);
                                            result.length := lua_ToNumber(l, -1);
                                            lua_pop(l, 1);
                                        end;
                                        end;
end;
    Function LuaObjAddTimer(l:Lua_State):integer; cdecl;
var obj:TBasicObject;
ref:TScriptReference;
    begin
if lua_gettop(l) <> 4 then lual_error(l, 'obj.addTimer expects 4 parameters (obj, interval, continuous, timerParam).', []);
                     obj := LuaToBasicObject(l, 1);
                     ref:=LuaGetParameterReference(l, 4);
Lua_PushLightUserData(l, obj.AddTimer(lua_ToInteger(l, 2), Lua_ToBoolean(l, 3), ref));
result:=1;
    end;
    Function LuaObjRemoveTimer(l:lua_state):integer; cdecl;
var obj:TBasicObject;
    begin
if lua_gettop(l) <> 2 then lual_error(l, 'obj.removeTimer expects 2 parameters (obj, timer).', []);
                     obj := LuaToBasicObject(l, 1);
                     obj.RemoveTimer(lua_ToUserData(l, 2));
result:=0;
    end;

    Function LuaWorldCreateGenericObject(l:lua_state):integer;     cdecl;
var flags:cardinal;
pos:TVector3F;
g:TGeometricalPrimitive;
directOcclusion,reverbOcclusion:single;
    begin
if (lua_GetTop(l) < 4) or (Lua_GetTop(l) > 5) then
lual_Error(l, 'world.createGenericObject expects 5 parameters (obj, flags, pos, primitive, soundGeometryParam).', []);
flags:=StrToFlags(LuaToString(l, 2));
pos:=LuaI^.LuaToVector3F(l, 3);
g:=LuaToGeometricalPrimitive(l, 4);
if lua_istable(l,5) then begin
lua_rawgeti(l, 5, 1);
directocclusion:=lua_tonumber(l, -1);
lua_pop(l,1);
lua_rawgeti(l, 5, 2);
reverbocclusion:=lua_tonumber(l, -1);
lua_pop(l,1);
LuaPushBasicObject(l, 1, world_CreateGenericObject(LuaNewGameObjectReference(l, 1), flags, pos, g, directOcclusion, reverbOcclusion));
end else
LuaPushBasicObject(l, 1, world_CreateGenericObject(LuaNewGameObjectReference(l, 1), flags, pos, g));
result:=0;
end;

                                                                                 Function LuaObjPitch(l:lua_state):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
if lua_gettop(l) <> 2 then
lual_error(l, 'obj.pitch expects 2 parameters (obj, angle).', []);
                     obj := LuaToBasicObject(l, 1);
if obj is TGenericObject then
(obj as TGenericObject).Pitch(Lua_ToNumber(l, 2)) else
Lual_Error(l, 'obj.pitch: passed obj is not a geometrical object.', []);
result:=0;
                                                                                 end;

Function LuaObjYaw(l:lua_state):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
if lua_gettop(l) <> 2 then
lual_error(l, 'obj.yaw expects 2 parameters (obj, angle).', []);
                     obj := LuaToBasicObject(l, 1);
if obj is TGenericObject then
(obj as TGenericObject).Yaw(Lua_ToNumber(l, 2)) else
Lual_Error(l, 'obj.yaw: passed obj is not a geometrical object.', []);
result:=0;
                                                                                 end;

                                                                                 Function LuaObjRoll(l:lua_state):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
if lua_gettop(l) <> 2 then
lual_error(l, 'obj.roll expects 2 parameters (obj, angle).', []);
                     obj := LuaToBasicObject(l, 1);
if obj is TGenericObject then
(obj as TGenericObject).Roll(Lua_ToNumber(l, 2)) else
Lual_Error(l, 'obj.roll: passed obj is not a geometrical object.', []);
result:=0;
                                                                                 end;

                                                                                 Function LuaObjSetPosition(l:lua_state):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
if lua_gettop(l) <> 2 then lual_error(l, 'obj.setPosition expects 2 parameters (obj, position).', []);
                     obj:=LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
(                     obj as TGenericObject).position := LuaI^.LuaToVector3F(l, 2) else
lual_error(l, 'obj.setPosition: passed object is not a geometrical object.', []);
result:=0;
                                                                                 end;
Function LuaObjPosition(l:lua_state):integer; cdecl;
var obj:TBasicObject;
begin
                     obj := LuaToBasicObject(l, 1);
if obj is TGenericObject then LuaI^.LuaPushVector3F(l, (obj as TGenericObject).position) else lua_pushnil(l);
result:=1;
end;
                                                                                 Function LuaObjMove(l:lua_state):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
if lua_gettop(l) < 2 then lual_error(l, 'obj.move expects 3 parameters (obj, vector, ignoreSolid).', []);
                     obj:=LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
lua_pushboolean(l, (obj as TGenericObject).move(LuaI^.LuaToVector3F(l, 2), lua_ToBoolean(l, 3))) else
lual_error(l, 'obj.move: passed object is not a geometrical object.', []);
result:=1;
                                                                                 end;

Function LuaObjRelativeMove(l:lua_state):integer; cdecl;
var obj:TBasicObject;
b:boolean;
                                                                                 begin
if lua_gettop(l) < 2 then lual_error(l, 'obj.relativeMove expects 3 parameters (obj, vector, ignoreSolid).', []);
                     obj:=LuaToBasicObject(l, 1);
                     if obj is TGenericObject then begin
b := (obj as TGenericObject).move(VectorTransform(LuaI^.LuaToVector3F(l, 2),
TGenericObject(obj).Geometry.orientation), lua_ToBoolean(l, 3));
lua_pushboolean(l, b);
end else
lual_error(l, 'obj.move: passed object is not a geometrical object.', []);
result:=1;
                                                                                 end;

                                                                                 Function LuaObjAttachSoundHandle(l:Lua_State):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
if lua_gettop(l) <> 2 then lual_error(l, 'obj.attachSoundHandle expects 2 parameters (obj, handle).', []);
                     obj := LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
(                     obj as TGenericObject).AttachSoundHandle(LuaI^.LuaToSoundHandle(l, 2))
else lual_error(l, 'obj.attachSoundHandle: passed object is not a generic object.', []);
result:=0;
                                                                                 end;

                                                                                 Function LuaObjDetachSoundHandle(l:Lua_State):integer; cdecl;
var obj:TBasicObject;
                                                                                 begin
                     if lua_gettop(l) <> 2 then lual_error(l, 'obj.detachSoundHandle expects 2 parameters (obj, handle).', []);
                     obj := LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
(                     obj as TGenericObject).DetachSoundHandle(LuaI^.LuaToSoundHandle(l, 2))
else lual_error(l, 'obj.DetachSoundHandle: passed object is not a generic object.', []);
result:=0;
                                                                                 end;

Function LuaObjPlaySound(l:Lua_State):integer; cdecl;
var obj:TBasicObject;
begin
                    if lua_gettop(l) < 3 then lual_error(l, 'obj.playSound expects 4 parameters (obj, res, pos, headrelative).', []);
                     obj := LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
LuaI^.LuaPushSoundHandle(l, (                     obj as TGenericObject).Play3DSound(Lua_ToString(l, 2), LuaI^.LuaToVector3F(l, 3), Lua_ToBoolean(l, 4)))
else lual_error(l, 'obj.playSound passed object is not a generic object.', []);
result:=1;
end;

Function LuaObjPlaySoundOnce(l:Lua_State):integer; cdecl;
var obj:TBasicObject;
begin
                    if lua_gettop(l) < 4 then lual_error(l, 'obj.playSoundOnce expects 4 parameters (obj, handle, res, pos, headrelative).', []);
                     obj := LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
                     LuaI^.LuaPushSoundHandle(l, (obj as TGenericObject).Play3DSoundOnce(LuaI^.LuaToSoundHandle(l, 2), Lua_ToString(l, 3), LuaI^.LuaToVector3F(l, 4), Lua_ToBoolean(l, 5)))
else lual_error(l, 'obj.playSoundOnce passed object is not a generic object.', []);
result:=1;
end;

Function LuaObjSetListener(l:lua_state):integer; cdecl;
var obj:TBasicObject;
begin
                    if lua_gettop(l) < 1 then lual_error(l, 'obj.setListener expects 2 parameters (obj, pos).', []);
                     obj := LuaToBasicObject(l, 1);
                     if obj is TGenericObject then begin
if lua_gettop(l) = 2 then (                     obj as TGenericObject).SetListener(LuaI^.LuaToVector3F(l, 2)) else
(                     obj as TGenericObject).SetListener(AffineVectorMake(0,0,0));
end else lual_error(l, 'obj.setListener passed object is not a generic object.', []);
result:=0;
end;
Function LuaWorldCreateDynamicObject(l:lua_state):integer;     cdecl;
var flags:cardinal;
pos:TVector3F;
g:TGeometricalPrimitive;
directOcclusion,reverbOcclusion:single;
    begin
if (lua_GetTop(l) < 4) or (Lua_GetTop(l) > 5) then
lual_Error(l, 'world.createDynamicObject expects 5 parameters (obj, flags, pos, primitive, soundGeometryParam).', []);
flags:=StrToFlags(LuaToString(l, 2));
pos:=LuaI^.LuaToVector3F(l, 3);
g:=LuaToGeometricalPrimitive(l, 4);
if lua_istable(l,5) then begin
lua_rawgeti(l, 5, 1);
directocclusion:=lua_tonumber(l, -1);
lua_pop(l,1);
lua_rawgeti(l, 5, 2);
reverbocclusion:=lua_tonumber(l, -1);
lua_pop(l,1);
LuaPushBasicObject(l, 1, world_CreateDynamicObject(LuaNewGameObjectReference(l, 1), flags, pos, g, directOcclusion, reverbOcclusion));
end else
LuaPushBasicObject(l, 1, world_CreateDynamicObject(LuaNewGameObjectReference(l, 1), flags, pos, g));
result:=0;
end;
Procedure ProcessEndFreeFallEvent(obj:TDynamicObject; speed:single);
begin
LuaPushGameObjectMethod(l, obj, ProcessEventsMethodName);
                                                                          lua_pushinteger(l, WORLDEVENT_ENDFREEFALL);
                                                                          lua_pushnumber(l, speed);
                                                                          try
LuaPCall(l, 3, 0, 0); //first parameter (self) was pushed by LuaPushGameObjectMethod
except
on e:Exception do core_Error(PChar('Error while calling processEvent method (WORLDEVENT_ENDFREEFALL): ' + e.Message), ECore_Main);
end;
end;
                Function LuaObjSetAccel(l:Lua_State):integer; cdecl;
var obj:TDynamicObject;
begin
if Lua_GetTop(l) <> 2 then lual_error(l, 'obj.setAccel expects 2 parameters (obj, accel).', []);
obj := LuaToBasicObject(l, 1) as TDynamicObject;
obj.Accel := LuaI^.LuaToVector3F(l, 2);
result:=0;
                end;

Function LuaObjSetRelativeAccel(l:Lua_State):integer; cdecl;
var obj:TDynamicObject;
begin
if Lua_GetTop(l) <> 2 then lual_error(l, 'obj.setRelativeAccel expects 2 parameters (obj, accel).', []);
obj := LuaToBasicObject(l, 1) as TDynamicObject;
obj.RelativeAccel := LuaI^.LuaToVector3F(l, 2);
result:=0;
                end;

Function LuaObjSetVelocity(l:Lua_State):integer; cdecl;
var obj:TDynamicObject;
begin
if Lua_GetTop(l) <> 2 then lual_error(l, 'obj.setVelocity expects 2 parameters (obj, velocity).', []);
obj := LuaToBasicObject(l, 1) as TDynamicObject;
obj.velocity := LuaI^.LuaToVector3F(l, 2);
result:=0;
                end;

Function LuaObjSetRelativeVelocity(l:Lua_State):integer; cdecl;
var obj:TDynamicObject;
begin
if Lua_GetTop(l) <> 2 then lual_error(l, 'obj.setRelativeVelocity expects 2 parameters (obj, velocity).', []);
obj := LuaToBasicObject(l, 1) as TDynamicObject;
obj.RelativeVelocity := LuaI^.LuaToVector3F(l, 2);
result:=0;
                end;
    Function LuaObjGetObjectUnderThis(l:lua_state):integer; cdecl;
var obj:TBasicObject;
    begin
if lua_gettop(l) <> 1 then lual_error(l, 'obj.getObjectUnderThis expects 1 parameter (self).', []);
obj := LuaToBasicObject(l, 1);
                     if obj is TGenericObject then
                     obj := (obj as TGenericObject).getObjectUnderThis();
if obj <> nil then
                     luaPushGameObjectByReference(l, obj.ScriptReference) else lua_pushnil(l);
                     result:=1;
    end;
    function LuaGameObjectIndex(l:Lua_State):integer; cdecl;
var s:string;
begin
result:=1;
s := LuaToString(l, 2);
if s = 'createBasic' then lua_PushCFunction(l, LuaWorldCreateBasicObject) else
if s = 'createGeneric' then lua_PushCFunction(l, LuaWorldCreateGenericObject) else
if s = 'createDynamic' then lua_PushCFunction(l, LuaWorldCreateDynamicObject) else
if s = 'registerInputActionMap' then lua_PushCFunction(l, LuaObjRegisterInputActionMap) else
if s = 'acquireInput' then lua_PushCFunction(l,LuaObjAcquireInput) else
if s = 'unacquireInput' then lua_PushCFunction(l, LuaObjUnacquireInput) else
if s = 'setFlags' then lua_pushCFunction(l, LuaObjSetFlag) else
if s = 'isFlagSet' then lua_PushCFunction(l, LuaObjIsFlagSet) else
if s = 'addTimer' then lua_PushCFunction(l, LuaObjAddTimer) else
if s = 'removeTimer' then lua_PushCFunction(l, LuaObjRemoveTimer) else
if s = 'pitch' then lua_PushCFunction(l, LuaObjPitch) else
if s = 'yaw' then lua_PushCFunction(l, LuaObjYaw) else
if s = 'roll' then Lua_PushCFunction(l, LuaObjRoll) else
if s = 'getObjectUnderThis' then lua_pushCFunction(l, LuaObjGetObjectUnderThis) else
if s = 'setPosition' then lua_PushCFunction(l, LuaObjSetPosition) else
if s = 'position' then lua_PushCFunction(l, luaObjPosition) else
if s = 'move' then lua_PushCFunction(l, LuaObjMove) else
if s = 'relativeMove' then lua_pushcfunction(l, LuaObjRelativeMove) else
if s = 'attachSoundHandle' then Lua_PushCFunction(l, LuaObjAttachSoundHandle) else
if s = 'detachSoundHandle' then Lua_PushCFunction(l, LuaObjDetachSoundHandle) else
if s = 'playSound' then lua_PushCFunction(l, LuaObjPlaySound) else
if s = 'playSoundOnce' then lua_PushCFunction(l, LuaObjPlaySoundOnce) else
if s = 'setListener' then lua_PushCFunction(l, LuaObjSetListener) else
if s = 'setAccel' then Lua_PushCFunction(l, LuaObjSetAccel) else
if s = 'setRelativeAccel' then Lua_PushCFunction(l, LuaObjSetRelativeAccel) else
if s = 'setVelocity' then lua_PushCFunction(l, LuaObjSetVelocity) else
if s = 'setRelativeVelocity' then lua_PushCFunction(l, LuaObjSetRelativeVelocity) else
result:=0;
end;

    procedure LuaRegisterGameObject(l:lua_state);
begin
lual_newmetatable(l, 'GameObject');
LuaPushString(l, '__gc');
lua_PushCFunction(l, LuaGameObjectIndex);
lua_RawSet(l, -3);
lua_pop(l, 1);
end;

                                                                                 Procedure RegisterLuaBindings; cdecl;
begin
if                LoadLuaLib <= 0 then begin
Core_Error(PChar('Can not load Lua library: ' + SysErrorMessage(GetLastError())), Ecore_Init);
exit;
end;
LuaI := Core_RequirePlugin(ScriptEngineI.LuaGUID);
l:=LuaI.GetState;
Lua_PushString(l,ObjTableName);
lua_CreateTable(l, 20, 0);
lua_RawSet(l, Lua_GlobalsIndex);
//event constants
LuaPushString(l, 'event_inputAction');
lua_PushInteger(l, EVENT_INPUTACTION);
Lua_RawSet(l, LUA_GLOBALSINDEX);
LuaPushString(l, 'event_gameAction');
Lua_PushInteger(l, EVENT_GAMEACTION);
Lua_RawSet(l, LUA_GLOBALSINDEX);
luaPushString(l, 'event_collision');
Lua_PushInteger(l, WORLDEVENT_COLLISION);
Lua_RawSet(l, lua_globalsindex);
luaPushString(l, 'event_timer');
lua_PushInteger(l, WORLDEVENT_TIMER);
                                Lua_RawSet(l, LUA_GLOBALSINDEX);
                                LuaPushString(l, 'event_startFreeFall');
                                lua_pushinteger(l, WORLDEVENT_STARTFREEFALL);
                                Lua_RawSet(l, LUA_GLOBALSINDEX);
                                LuaPushString(l, 'event_endFreeFall');
                                lua_pushinteger(l, WORLDEVENT_ENDFREEFALL);
                                Lua_RawSet(l, LUA_GLOBALSINDEX);
LuaRegisterGameObject(l);
LuaRegister(l, 'world.init', LuaWorldInit);
LuaRegister(l, 'world.release', LuaWorldRelease);
LuaRegister(l, 'world.pushGameEvent', LuaWorld_PushGameEvent);
LuaRegister(l, 'world.createBasicObject', LuaWorldCreateBasicObject);
LuaRegister(l, 'world.releaseObject', LuaWorldReleaseGameObject);
luaRegister(l, 'obj.setFlag', LuaObjSetFlag);
LuaRegister(l, 'obj.isFlagSet', LuaObjIsFlagSet);
LuaRegister(l, 'obj.registerInputActionMap', LuaObjRegisterInputActionMap);
LuaRegister(l, 'obj.acquireInput', LuaObjAcquireInput);
luaRegister(l, 'obj.unacquireInput', luaObjUnacquireInput);
LuaRegister(l, 'obj.addTimer', LuaObjAddTimer);
LuaRegister(l, 'obj.removeTimer', LuaObjRemoveTimer);
luaRegister(l, 'world.createGenericObject', LuaWorldCreateGenericObject);
LuaRegister(l, 'obj.pitch', LuaObjPitch);
LuaRegister(l, 'obj.yaw', LuaObjYaw);
luaRegister(l, 'obj.roll', LuaObjRoll);
//Geometrical primitive types
luaPushString(l, 'gp_sphere');
lua_PushInteger(l, cardinal(gp_sphere));
lua_rawset(l, lua_globalsindex);
    luaPushString(l, 'gp_box');
    lua_PushInteger(l, cardinal(gp_AABB));
                                lua_rawset(l, lua_globalsindex);
                                LuaRegister(l, 'obj.setPosition', LuaObjSetPosition);
                                luaRegister(l, 'obj.move', LuaObjMove);
LuaRegister(l, 'obj.attachSoundHandle', LuaObjAttachSoundHandle);
LuaRegister(l, 'obj.detachSoundHandle', LuaObjdetachSoundHandle);
LuaRegister(l, 'obj.playSound', LuaObjPlaySound);
luaRegister(l, 'obj.playSoundOnce', LuaObjPlaySoundOnce);
LuaRegister(l, 'obj.setListener', LuaObjSetListener);
//dynamic object
LuaRegister(l, 'world.createDynamicObject', LuaWorldCreateDynamicObject);
LuaRegister(l, 'obj.setAccel', LuaObjSetAccel);
LuaRegister(l, 'obj.setRelativeAccel', LuaObjSetRelativeAccel);
LuaRegister(l, 'obj.setVelocity', LuaObjSetVelocity);
LuaRegister(l, 'obj.setRelativeVelocity', LuaObjSetRelativeVelocity);
LuaRegister(l, 'gameObjectIndex', LuaGameObjectIndex);
LuaRegister(l, 'obj.relativeMove', LuaObjRelativeMove);
luaRegister(l, 'obj.getObjectUnderThis', luaObjGetObjectUnderThis);
                                end;
end.
